package cn.com.dcsgo.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Modifier;
import java.util.ArrayList;

/**
 * LogAdvicePro
 *
 * @author Dcsgo
 * @since 2025/2/6 12:25
 */
@Aspect
@Component
@Order(3)//指定切面优先级，数字越大优先级越低，也就是后执行(作用于同一个目标的多个切面之间是层层包裹的)
public class LogAdvicePro {
    /**
     * @param joinPoint 连接点信息，spring将自动给该参数赋值，JointPoint封装了目标类及其方法的详细信息
     */
    @Before("execution(* cn.com.dcsgo.service.*.*(..))")
    public void before(JoinPoint joinPoint) {
        System.out.println("running: " + getMethodInfo(joinPoint));
    }

    /**
     * @param joinPoint joinPoint
     * @param result    通过 @AfterReturning 注解的属性 returning 可指定接受被代理对象方法返回结果的参数
     */
    @AfterReturning(value = "execution(* cn.com.dcsgo.service.*.*(..))", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("processed: " + getMethodInfo(joinPoint) + " result: " + result);
    }


    @After("execution(* cn.com.dcsgo.service.*.*(..))")
    public void after(JoinPoint joinPoint) {
        System.out.println("finished: " + getMethodInfo(joinPoint));
    }

    /**
     * @param joinPoint joinPoint
     * @param throwable 通过 @AfterThrowing 注解的属性 throwing 可指定接受被代理对象产生异常的对象
     */
    @AfterThrowing(value = "execution(* cn.com.dcsgo..impl.*.*(..))", throwing = "throwable")
    public void afterThrowing(JoinPoint joinPoint, Throwable throwable) {
        System.out.println("error: " + getMethodInfo(joinPoint));
        System.out.println("\t" + throwable.getMessage());
    }

    private String getMethodInfo(JoinPoint joinPoint) {
        String targetClassName = joinPoint.getTarget().getClass().getName();
        Object[] args = joinPoint.getArgs();
        ArrayList<String> argsStr = new ArrayList<>();
        for (Object arg : args) {
            String argTypeAndValue = arg.getClass().getSimpleName() +
                    " " + arg.toString();
            argsStr.add(argTypeAndValue);
        }
        Signature signature = joinPoint.getSignature();
        int modifiers = signature.getModifiers();
        //方法修饰符
        String modifierStr = Modifier.toString(modifiers);
        String methodName = signature.getName();
        return targetClassName + "." + methodName + "(" + argsStr + ")";
    }
}
